<!DOCTYPE html>
<html>
<!--
Copyright 2008 The Closure Library Authors. All Rights Reserved.

Use of this source code is governed by the Apache License, Version 2.0.
See the COPYING file for details.
-->
<!--
Author:  attila@google.com (Attila Bodis)
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>Closure Unit Tests - goog.testing.PerformanceTimer</title>
  <script src="../base.js"></script>
  <script>
    goog.require('goog.async.Deferred');
    goog.require('goog.dom');
    goog.require('goog.math');
    goog.require('goog.testing.MockClock');
    goog.require('goog.testing.PerformanceTimer');
    goog.require('goog.testing.jsunit');
  </script>
</head>
<body>
  <div id="sandbox"></div>
  <script>
    var mockClock;
    var sandbox = document.getElementById('sandbox');
    var timer;

    function setUp() {
      mockClock = new goog.testing.MockClock(true);
      timer = new goog.testing.PerformanceTimer();
    }

    function tearDown() {
      mockClock.dispose();
      timer = null;
      goog.dom.removeChildren(sandbox);
    }

    function testConstructor() {
      assertTrue('Timer must be an instance of goog.testing.PerformanceTimer',
          timer instanceof goog.testing.PerformanceTimer);
      assertEquals('Timer must collect the default number of samples', 10,
          timer.getNumSamples());
      assertEquals('Timer must have the default timeout interval', 5000,
          timer.getTimeoutInterval());
    }

    function testRun_noSetUpOrTearDown() {
      runAndAssert(false, false, false);
    }

    function testRun_withSetup() {
      runAndAssert(true, false, false);
    }

    function testRun_withTearDown() {
      runAndAssert(false, true, false);
    }

    function testRun_withSetUpAndTearDown() {
      runAndAssert(true, true, false);
    }

    function testRunAsync_noSetUpOrTearDown() {
      runAndAssert(false, false, true);
    }

    function testRunAsync_withSetup() {
      runAndAssert(true, false, true);
    }

    function testRunAsync_withTearDown() {
      runAndAssert(false, true, true);
    }

    function testRunAsync_withSetUpAndTearDown() {
      runAndAssert(true, true, true);
    }

    function runAndAssert(useSetUp, useTearDown, runAsync) {
      var fakeExecutionTime = [100, 95, 98, 104, 130, 101, 96, 98, 90, 103]
      var count = 0;
      var testFunction = function() {
        mockClock.tick(fakeExecutionTime[count++]);
        if (runAsync) {
          var deferred = new goog.async.Deferred();
          deferred.callback();
          return deferred;
        }
      };

      var setUpCount = 0;
      var setUpFunction = function() {
        // Should have no effect on total time.
        mockClock.tick(7);
        setUpCount++;
        if (runAsync) {
          var deferred = new goog.async.Deferred();
          deferred.callback();
          return deferred;
        }
      };

      var tearDownCount = 0;
      var tearDownFunction = function() {
        // Should have no effect on total time.
        mockClock.tick(11);
        tearDownCount++;
        if (runAsync) {
          var deferred = new goog.async.Deferred();
          deferred.callback();
          return deferred;
        }
      };

      // Fast test function should complete successfully in under 5 seconds...
      var task = new goog.testing.PerformanceTimer.Task(testFunction);
      if (useSetUp) {
        task.withSetUp(setUpFunction);
      }
      if (useTearDown) {
        task.withTearDown(tearDownFunction);
      }
      if (runAsync) {
        var assertsRan = false;
        var deferred = timer.runAsyncTask(task);
        deferred.addCallback(
            function(results) {
              assertsRan = assertResults(results, useSetUp, useTearDown,
                  setUpCount, tearDownCount, fakeExecutionTime);
            });
        assertTrue(assertsRan);
      } else {
        var results = timer.runTask(task);
        assertResults(results, useSetUp, useTearDown, setUpCount, tearDownCount,
            fakeExecutionTime);
      }
    }

    function assertResults(results, useSetUp, useTearDown, setUpCount,
        tearDownCount, fakeExecutionTime) {
      assertNotNull('Results must be available.', results);

      assertEquals('Average is wrong.',
          goog.math.average.apply(null, fakeExecutionTime), results['average']);
      assertEquals('Standard deviation is wrong.',
          goog.math.standardDeviation.apply(null, fakeExecutionTime),
          results['standardDeviation']);

      assertEquals('Count must be as expected.', 10, results['count']);
      assertEquals('Maximum is wrong.', 130, results['maximum']);
      assertEquals('Mimimum is wrong.', 90, results['minimum']);
      assertEquals('Total must be a nonnegative number.',
          goog.math.sum.apply(null, fakeExecutionTime), results['total']);

      assertEquals('Set up count must be as expected.',
          useSetUp ? 10 : 0, setUpCount);
      assertEquals('Tear down count must be as expected.',
          useTearDown ? 10 : 0, tearDownCount);

      return true;
    }

    function testTimeout() {
      var count = 0;
      var testFunction = function() {
        mockClock.tick(100);
        ++count;
      };

      timer.setNumSamples(200);
      timer.setTimeoutInterval(2500);
      var results = timer.run(testFunction);

      assertNotNull('Results must be available', results);
      assertEquals('Count is wrong', count, results['count']);
      assertTrue('Count must less than expected',
          results['count'] < timer.getNumSamples());
    }

    function testCreateResults() {
      var samples = [53, 0, 103];
      var expectedResults = {
        'average': 52,
        'count': 3,
        'maximum': 103,
        'minimum': 0,
        'standardDeviation': goog.math.standardDeviation.apply(null, samples),
        'total': 156
      };
      assertObjectEquals(
          expectedResults,
          goog.testing.PerformanceTimer.createResults(samples));
    }
  </script>
</body>
</html>
